/***************************************************************************
 *   Copyright (C) 2007 by Grzegorz Latarowski, Maciej Gajewski            *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

// Qty
#include <QDateTime>
#include <QImage>
#include <QRgb>

// local
#include "autoclient.h"
#include "gexception.h"
#include "autopackets.h"


// --------------------------- constructor -----------------------------------
GAutoClient::GAutoClient()
{
	_timeout	= 5000; // 5 sec
	_requestId	= (int)QDateTime::currentDateTime().toTime_t();
	
	connect( &_socket, SIGNAL( stateChanged( QAbstractSocket::SocketState ) ),
			  this, SLOT( socketStateChanged( QAbstractSocket::SocketState ) ) );
}
// ---------------------------------------------------------------------------


// --------------------------- destructor ------------------------------------
GAutoClient::~GAutoClient()
{
	// nothing
}
// ---------------------------------------------------------------------------


// --------------------- GAutoClient::socketStateChanged() -------------------
void GAutoClient::socketStateChanged( QAbstractSocket::SocketState socketState )
{
	switch( socketState )
	{
		case QAbstractSocket::UnconnectedState:
		{
			// emit that socket disconnectes
			emit disconnected();
		}
		break;
		
		default:
			break;
	}
}
// ---------------------------------------------------------------------------
	

// --------------------------- connectToHost ---------------------------------
/// Connects to specified host synchronously. May throw UQTimeoutError
void GAutoClient::connectToHost( const QString & hostName, quint16 port )
{
	_socket.connectToHost( hostName, port );

	if ( ! _socket.waitForConnected( _timeout ) )
	{
		throw GTimeoutError( _socket.errorString() );
	}
}
// ---------------------------------------------------------------------------


// --------------------------- disconnectFromHost ----------------------------
/// Disconects from host
void GAutoClient::disconnectFromHost()
{
	_socket.disconnectFromHost();
	
	// if socket is already disconnected than skip waiting for disconnecting
	if( _socket.state() != QAbstractSocket::UnconnectedState )
	{
		if ( ! _socket.waitForDisconnected( _timeout ) )
		{
			throw GTimeoutError( _socket.errorString() );
		}
	}
}
// ---------------------------------------------------------------------------


// --------------------------- isConnected -----------------------------------
bool GAutoClient::isConnected()
{
	return _socket.state() == QAbstractSocket::ConnectedState;
}
// ---------------------------------------------------------------------------


// --------------------------- waitForReply --------------------------------
/// Waits for reply packet with specified request id
GAutoReply* GAutoClient::waitForReply( uint requestId )
{
	forever
	{
		// wait for any packet
		GAutoPacket * pPacket = waitForPacket();

		// is this a reply?
		GAutoReply * pReply = qobject_cast< GAutoReply * >( pPacket );
		if ( pReply )
		{
			if ( pReply->requestId() == requestId )
			{
				return pReply;
			}
			else
			{
				qDebug("GAutoClient::waitForReply: unexpected reply, request id=%d", pReply->requestId() );
			}
		}
		else
		{
			return NULL;
		}
		// igore al other packets
	}
}
// ---------------------------------------------------------------------------


// --------------------------- waitForPacket ---------------------------------
/// Waits for incomng packet
GAutoPacket * GAutoClient::waitForPacket()
{
	if ( isConnected() )
	{
		GHeader		header;

		// read header
		header.readFromSocket( & _socket, _timeout );
		// create apropriate packet
		GAutoPacket * pPacket = GAutoPacket::createPacket( header );
		// read packet
		if ( pPacket )
		{
			pPacket->readFromSocket( & _socket, _timeout );
			//qDebug("Client: packet of type %x got", (int)pPacket->packetType()); // TODO remove

			return pPacket;
		}
		
	}

	return NULL;
}
// ---------------------------------------------------------------------------


// --------------------------- sendPacket ------------------------------------
/// Sends packet
void GAutoClient::sendPacket( const GAutoPacket & packet )
{
	if ( isConnected() )
	{
		GHeader header = packet.header();

		header.writeToSocket( & _socket, _timeout );
		packet.writeToSocket( & _socket, _timeout );
		
		//qDebug("Client: packet of type %x send", (int)packet.packetType()); // TODO remove
	}
}

// --------------------------- getRequestId ----------------------------------
/// Returns session-uniqe request id
quint32 GAutoClient::getRequestId()
{
	_requestId ++;
	return _requestId;
}
// ---------------------------------------------------------------------------


// ------------------------- GAutoClient::frame() ----------------------------
QPixmap GAutoClient::frame()
{
	if ( isConnected() )
	{
		// create request packet
		quint32 requestId = getRequestId();
		GAutoRequest request( GAutoRequest::REQUEST_FRAME, requestId );

		// send packet
		sendPacket( request );

		// wait for respones
		GAutoReply * pReply = waitForReply( requestId );

		GAutoReplyFrame * pReplyFrame = qobject_cast< GAutoReplyFrame * >(pReply);

		if ( pReplyFrame )
		{
			quint16 width = pReplyFrame->width();
			quint16 height = pReplyFrame->height();
			QByteArray imageData = pReplyFrame->image();
			
			QImage image( width, height, QImage::Format_RGB32 );
	
			char * byte = imageData.data();
			for( int y = 0; y < height; y++ )
			{
				for( int x = 0; x < width; x++ )
				{
					if ( byte< imageData.data() + imageData.size()  )
					{
						image.setPixel( x, y, qRgb( *byte, *byte, *byte ) );
						byte++;
					}
				}
			}
				// succes 
			return QPixmap::fromImage( image );
		}
	}
	
	return QPixmap();
}
// ---------------------------------------------------------------------------


// ----------------- GAutoClient::sendXmlConfig() ----------------------------
void GAutoClient::sendXmlConfig( QByteArray & fileData )
{
	GAutoXmlConfig xmlConfig;
	xmlConfig.setData( fileData );
	sendPacket( xmlConfig );
}
// ---------------------------------------------------------------------------


// ------------------ GAutoClient::sendMarkers() -----------------------------
void GAutoClient::sendMarkers( pimage_t markers )
{
	GAutoMarkers markersPacket;
	markersPacket.setMarkers( markers );
	sendPacket( markersPacket );
}
// ---------------------------------------------------------------------------
	
	
// ------------------- GAutoClient::sendRoi() --------------------------------
void GAutoClient::sendRoi( pimage_t roi )
{
	GAutoRoi roiPacket;
	roiPacket.setRoi( roi );
	sendPacket( roiPacket );
}
// ---------------------------------------------------------------------------
	
	
// -------------------- GAutoClient::sendParams() ----------------------------
void GAutoClient::sendParams( const QVariantMap & params )
{
	GAutoParams paramsPacket;
	paramsPacket.setParams( params );
	sendPacket( paramsPacket );
	qDebug( "params send" );
}
// ---------------------------------------------------------------------------
	

// eof
